#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "params.h"
#include "types.h"
#include "defs.h"
#include "parser.h"
#include "jitcc.h"
#include "runtime.h"

#define IDX (inst->r1)
#define FP (regs[X_FP])
#define PC (regs[X_PC])
#define RD (inst->r0)
#define RS1 (inst->r1)
#define RS2 (inst->r2)
#define IMM (inst->imm)
#define SHMASK(x) (0xFF&x)
#define V (inst->v)
#define R (regs)

#define Z(x) ((uint64)x)
#define S(x) ((int64)x)


int
rtexec_asgn (uint64 * regs, struct ins *  inst) {
    PC++;
    assignvar (regs, inst);
    return SUCCESS;
}


int // 需检查bug
rtexec_cast (uint64 * regs, struct ins *  inst) {
    PC++;
    //*(int64*)(FP+V->stackoff) = 0;
    if (!(V->flg&F_VAR_VALID)) return ERROR;
    if((V->flg&F_VAR_STACK)) {
        switch (V->type) {
            /* 有符号cast */
            case VAR_I8 : {
                *(int64*)(FP+V->stackoff) = *((int8*)(FP+V->stackoff));
                break;
            }
            case VAR_I16 : {
                *(int64*)(FP+V->stackoff) = *((int16*)(FP+V->stackoff));
                break;
            }
            case VAR_I32 : {
                *(int64*)(FP+V->stackoff) = *((int32*)(FP+V->stackoff));
                break;
            }
            case VAR_I64 : {
                *(int64*)(FP+V->stackoff) = *((int64*)(FP+V->stackoff));
                break;
            }
            case VAR_U8 : {
                *(uint64*)(FP+V->stackoff) = *((uint8*)(FP+V->stackoff));
                break;
            }
            case VAR_U16 : {
                *(uint64*)(FP+V->stackoff) = *((uint16*)(FP+V->stackoff));
                break;
            }
            case VAR_U32 : { 
                *(uint64*)(FP+V->stackoff) = *((uint32*)(FP+V->stackoff));
                break;
            }
            case VAR_U64 : {
                *(uint64*)(FP+V->stackoff) = *((uint64*)(FP+V->stackoff));
                break;
            }
            case VAR_STR : {
                return ERROR;
                break;
            }
            case VAR_SPACE : {
                return ERROR;
                break;
            }
            default : {
                return ERROR;
                break;
            }
        }
        V->type = inst->casttype;
        return SUCCESS;
    }
    if ((V->flg&F_VAR_HEAP)) {
        switch (V->type) {
            case VAR_I8 : {
                *(int64*)(V->heapaddr) = (int64)*(int8*)(V->heapaddr);
                V->type = VAR_I8;
                break;
            }
            case VAR_I16 : {
                *(int64*)(V->heapaddr) = (int64)*(int16*)(V->heapaddr);
                V->type = VAR_I16;
                break;
            }
            case VAR_I32 : {
                *(int64*)(V->heapaddr) = (int64)*(int32*)(V->heapaddr);
                V->type = VAR_I32;
                break;
            }
            case VAR_I64 : {
                *(int64*)(V->heapaddr) = (int64)*(int64*)(V->heapaddr);
                V->type = VAR_I64;
                break;
            }
            case VAR_U8 : {
                *(uint64*)(V->heapaddr) = (uint64)*(uint8*)(V->heapaddr);
                V->type = VAR_U8;
                break;
            }
            case VAR_U16 : {
                *(uint64*)(V->heapaddr) = (uint64)*(uint16*)(V->heapaddr);
                V->type = VAR_U16;
                break;
            }
            case VAR_U32 : {
                *(uint64*)(V->heapaddr) = (uint64)*(uint32*)(V->heapaddr);
                V->type = VAR_U32;
                break;
            }
            case VAR_U64 : {
                *(uint64*)(V->heapaddr) = (uint64)*(uint64*)(V->heapaddr);
                V->type = VAR_U64;
                break;
            }
            case VAR_STR : {
                return ERROR;
                break;
            }
            case VAR_SPACE : {
                return ERROR;
                break;
            }
            default : {
                return ERROR;
                break;
            }
        }
        return SUCCESS;
    }
    return ERROR;
}

int
rtexec_li (uint64 * regs, struct ins *  inst) {
    R[RD] = S(IMM);
    PC++;
    return SUCCESS;
}

int
rtexec_addi (uint64 * regs, struct ins *  inst) {
    R[RD] = S(R[RS1]) + S(IMM);
    PC++;
    return SUCCESS;
}

int
rtexec_slti (uint64 * regs, struct ins *  inst) {
    R[RD] = S(R[RS1]) < S(IMM);
    PC++;
    return SUCCESS;
}

int
rtexec_sltiu (uint64 * regs, struct ins *  inst) {
    R[RD] = Z(R[RS1]) < Z(IMM);
    PC++;
    return SUCCESS;
}

int
rtexec_xori (uint64 * regs, struct ins *  inst) {
    R[RD] = S(R[RS1]) ^ S(IMM); 
    PC++;
    return SUCCESS;
}

int
rtexec_ori (uint64 * regs, struct ins *  inst) {
    R[RD] = S(R[RS1]) | S(IMM);
    PC++;
    return SUCCESS;
}

int
rtexec_andi (uint64 * regs, struct ins *  inst) {
    R[RD] = S(R[RS1]) & S(IMM);
    PC++;
    return SUCCESS;
}

int
rtexec_slli (uint64 * regs, struct ins *  inst) {
    R[RD] = Z(R[RS1]) << Z(SHMASK(IMM)); 
    PC++;
    return SUCCESS;
}

int
rtexec_srli (uint64 * regs, struct ins *  inst) {
    R[RD] = Z(R[RS1]) >> Z(SHMASK(IMM));
    PC++;
    return SUCCESS;
}

int
rtexec_srai (uint64 * regs, struct ins *  inst) {
    R[RD] = S(R[RS1]) >> Z(SHMASK(IMM));
    PC++;
    return SUCCESS;
}

int
rtexec_add (uint64 * regs, struct ins *  inst) {
    R[RD] = S(R[RS1]) + S(R[RS2]);
    PC++;
    return SUCCESS;
}

int
rtexec_sub (uint64 * regs, struct ins *  inst) {
    R[RD] = S(R[RS1]) - S(R[RS2]);
    PC++;
    return SUCCESS;
}

int
rtexec_sll (uint64 * regs, struct ins *  inst) {
    R[RD] = Z(R[RS1]) << Z(SHMASK(R[RS2]));
    PC++;
    return SUCCESS;
}

int
rtexec_slt (uint64 * regs, struct ins *  inst) {
    R[RD] = S(R[RS1]) < S(R[RS2]); 
    PC++;
    return SUCCESS;
}

int
rtexec_sltu (uint64 * regs, struct ins *  inst) {
    R[RD] = Z(R[RS1]) < Z(R[RS2]); 
    PC++;
    return SUCCESS;
}

int
rtexec_xor (uint64 * regs, struct ins *  inst) {
    R[RD] = R[RS1] ^ R[RS2];
    PC++;
    return SUCCESS;
}

int
rtexec_srl (uint64 * regs, struct ins *  inst) {
    R[RD] = Z(R[RS1]) >> S(SHMASK(R[RS2]));
    PC++;
    return SUCCESS;
}

int
rtexec_sra (uint64 * regs, struct ins *  inst) {
    R[RD] = S(R[RS1]) >> S(SHMASK(R[RS2]));
    PC++;
    return SUCCESS;
}
int
rtexec_or (uint64 * regs, struct ins *  inst) {
    R[RD] = R[RS1] | R[RS2];
    PC++;
    return SUCCESS;
}

int
rtexec_and (uint64 * regs, struct ins *  inst) {
    R[RD] = R[RS1] & R[RS2];
    PC++;
    return SUCCESS;
}

int
rtexec_not (uint64 * regs, struct ins *  inst) {
    R[RD] = ~R[RS1];
    PC++;
    return SUCCESS;
}

int // NOTE:越界检测 ! 存在bug
rtexec_ldi (uint64 * regs, struct ins *  inst) {
    PC++;
    void * v;
    if (V->type == VAR_STR || 
        V->type == VAR_SPACE) {
        if ((V->flg&F_VAR_STACK))
            v = *((void**)(FP + V->stackoff));
        else if ((V->flg & F_VAR_HEAP))
            v = *((void**)(V->heapaddr));
        else
            return ERROR;
        switch (inst->iadr) {
            case IADR_I8: {
                v += R[RS1];
                R[RD] = *((int8*)v);
                break;
            }
            case IADR_I16: {
                v += (R[RS1] << 1);
                R[RD] = *((int16*)v);
                break;
            }
            case IADR_I32: {
                v += (R[RS1] << 2);
                R[RD] = *((int32*)v);
                break;
            }
            case IADR_I64: {
                v += (R[RS1] << 3);
                R[RD] = *((int64*)v);
                break;
            }
            case IADR_U8: {
                v += R[RS1];
                R[RD] = *((uint8*)v);
                break;
            }
            case IADR_U16: {
                v += (R[RS1] << 1);
                R[RD] = *((uint16*)v);
                break;
            }
            case IADR_U32: {
                v += (R[RS1] << 2);
                R[RD] = *((uint32*)v);
                break;
            }
            case IADR_U64: {
                v += (R[RS1] << 3);
                R[RD] = *((uint64*)v);
                break;
            }
            default : {
                return ERROR;
            }
        }
        return SUCCESS;
    }
    return ERROR;
}

int
rtexec_sti (uint64 * regs, struct ins *  inst) {
    PC++;
    void * v;
    #define RS RD
    if (V->type == VAR_STR || 
        V->type == VAR_SPACE) {
        if ((V->flg&F_VAR_STACK))
            v = *((void**)(FP + V->stackoff));
        else if ((V->flg & F_VAR_HEAP))
            v = *((void**)(V->heapaddr));
        else
            return ERROR;
        switch (inst->iadr) {
            case IADR_I8: {
                v += R[RS1];
                *(int8*)v = (int8)R[RS];
                break;
            }
            case IADR_I16: {
                v += (R[RS1] << 1);
                *(int16*)v = (int16)R[RS];
                break;
            }
            case IADR_I32: {
                v += (R[RS1] << 2);
                *(int32*)v = (int32)R[RS];
                break;
            }
            case IADR_I64: {
                v += (R[RS1] << 3);
                *(int64*)v = (int64)R[RS];
                break;
            }
            case IADR_U8: {
                v += R[RS1];
                *(uint8*)v = (uint8)R[RS];
                break;
            }
            case IADR_U16: {
                v += (R[RS1] << 1);
                *(uint16*)v = (uint16)R[RS];
                break;
            }
            case IADR_U32: {
                v += (R[RS1] << 2);
                *(uint32*)v = (uint32)R[RS];
                break;
            }
            case IADR_U64: {
                v += (R[RS1] << 3);
                *(uint64*)v = (uint64)R[RS];
                break;
            }
            default : {
                return ERROR;
            }
        }
        return SUCCESS;
    }
    return ERROR;
    #undef RS
}

int
rtexec_ld (uint64 * regs, struct ins *  inst) {
    PC++;
    if (!(V->flg&F_VAR_VALID)) return ERROR;
    if((V->flg&F_VAR_STACK)) {
        switch (V->type) {
            case VAR_I8 : {
                R[RD] = (int64)*(int8*)(FP+V->stackoff);
                break;
            }
            case VAR_I16 : {
                R[RD] = (int64)*(int16*)(FP+V->stackoff);
                break;
            }
            case VAR_I32 : {
                R[RD] = (int64)*(int32*)(FP+V->stackoff);
                break;
            }
            case VAR_I64 : {
                R[RD] = *(int64*)(FP+V->stackoff);
                break;
            }
            case VAR_U8 : {
                R[RD] = *(uint8*)(FP+V->stackoff);
                break;
            }
            case VAR_U16 : {
                R[RD] = *(uint16*)(FP+V->stackoff);
                break;
            }
            case VAR_U32 : {
                R[RD] = *(uint32*)(FP+V->stackoff);
                break;
            }
            case VAR_U64 : {
                R[RD] = *(uint64*)(FP+V->stackoff);
                break;
            }
            case VAR_STR : {
                R[RD] = *(uint64*)(FP+V->stackoff);
                break;
            }
            case VAR_SPACE : {
                R[RD] = *(uint64*)(FP+V->stackoff);
                break;
            }
            default : {
                return ERROR;
                break;
            }
        }
        return SUCCESS;
    }
    if ((V->flg&F_VAR_HEAP)) {
        switch (V->type) {
            case VAR_I8 : {
                R[RD] = (int64)*(int8*)(V->heapaddr);
                break;
            }
            case VAR_I16 : {
                R[RD] = (int64)*(int16*)(V->heapaddr);
                break;
            }
            case VAR_I32 : {
                R[RD] = (int64)*(int32*)(V->heapaddr);
                break;
            }
            case VAR_I64 : {
                R[RD] = *(int64*)(V->heapaddr);
                break;
            }
            case VAR_U8 : {
                R[RD] = *(uint8*)(V->heapaddr);
                break;
            }
            case VAR_U16 : {
                R[RD] = *(uint16*)(V->heapaddr);
                break;
            }
            case VAR_U32 : {
                R[RD] = *(uint32*)(V->heapaddr);
                break;
            }
            case VAR_U64 : {
                R[RD] = *(uint64*)(V->heapaddr);
                break;
            }
            case VAR_STR : {
                R[RD] = *(uint64*)(V->heapaddr);
                break;
            }
            case VAR_SPACE : {
                R[RD] = *(uint64*)(V->heapaddr);
                break;
            }
            default : {
                return ERROR;
                break;
            }
        }
        return SUCCESS;
    }
    return ERROR;
}

int
rtexec_st (uint64 * regs, struct ins *  inst) {
    PC++;
    #define RS RD
    if (!(V->flg&F_VAR_VALID)) return ERROR;
    if((V->flg&F_VAR_STACK)) {
        switch (V->type) {
            case VAR_I8 : {
                *(uint64*)(FP+V->stackoff) = (int8)R[RS];
                break;
            }
            case VAR_I16 : {
                *(uint64*)(FP+V->stackoff) = (int16)R[RS];
                break;
            }
            case VAR_I32 : {
                *(uint64*)(FP+V->stackoff) = (int32)R[RS];
                break;
            }
            case VAR_I64 : {
                *(uint64*)(FP+V->stackoff) = (int64)R[RS];
                break;
            }
            case VAR_U8 : {
                *(uint64*)(FP+V->stackoff) = (uint8)R[RS];
                break;
            }
            case VAR_U16 : {
                *(uint64*)(FP+V->stackoff) = (uint16)R[RS];
                break;
            }
            case VAR_U32 : {
                *(uint64*)(FP+V->stackoff) = (uint32)R[RS];
                break;
            }
            case VAR_U64 : {
                *(uint64*)(FP+V->stackoff) = (uint64)R[RS];
                break;
            }
            case VAR_STR : {
                break;
            }
            case VAR_SPACE : {
                break;
            }
            default : {
                return ERROR;
                break;
            }
        }
        return SUCCESS;
    }
    if ((V->flg&F_VAR_HEAP)) {
        switch (V->type) {
            case VAR_I8 : {
                *(uint64*)(V->heapaddr) = (int8)R[RS];
                break;
            }
            case VAR_I16 : {
                *(uint64*)(V->heapaddr) = (int16)R[RS];
                break;
            }
            case VAR_I32 : {
                *(uint64*)(V->heapaddr) = (int32)R[RS];
                break;
            }
            case VAR_I64 : {
                *(uint64*)(V->heapaddr) = (int64)R[RS];
                break;
            }
            case VAR_U8 : {
                *(uint64*)(V->heapaddr) = (uint8)R[RS];
                break;
            }
            case VAR_U16 : {
                *(uint64*)(V->heapaddr) = (uint16)R[RS];
                break;
            }
            case VAR_U32 : {
                *(uint64*)(V->heapaddr) = (uint32)R[RS];
                break;
            }
            case VAR_U64 : {
                *(uint64*)(V->heapaddr) = (uint64)R[RS];
                break;
            }
            case VAR_STR : {
                break;
            }
            case VAR_SPACE : {
                break;
            }
            default : {
                return ERROR;
                break;
            }
        }
        return SUCCESS;
    }
    return ERROR;
    #undef RS
}

// int // psudo instruction
// rtexec_callr (uint64 * regs, struct ins *  inst) {

// }

// old FP | oldfunc varspace | PC | FP | new FP 
int
rtexec_call (uint64 * regs, struct ins *  inst) {
    *(uint64*)(FP+inst->varspace) = PC+1;// PC压栈
    *(uint64*)(FP+inst->varspace+8) = FP; // FP压栈
    FP=FP+inst->varspace+16; // 下一个栈帧,当前为新栈帧
    PC = inst->j;
    return SUCCESS;
}

// old FP | oldfunc varspace | PC (new FP-16) | FP(new FP - 8) | new FP 
int
rtexec_ret (uint64 * regs, struct ins *  inst) {
    (void) inst;
    freeallvar (regs); // 释放当前函数所有局部变量
    PC = *(uint64*)(FP-16); // PC出栈
    FP = *(uint64*)(FP-8); // FP出栈,当前为旧栈帧
    return SUCCESS;
}

int
rtexec_mv (uint64 * regs, struct ins *  inst) {
    R[RD] = R[RS1];
    PC++;
    return SUCCESS;
}

int
rtexec_b (uint64 * regs, struct ins *  inst) {
    PC = inst->j;
    return SUCCESS;
}

int
rtexec_beq (uint64 * regs, struct ins *  inst) {
    if (R[RS1] == R[RS2])
        PC = inst->j;
    else
        PC++;
    return SUCCESS;
}

int
rtexec_bne (uint64 * regs, struct ins *  inst) {
    if (R[RS1] != R[RS2])
        PC = inst->j;
    else
        PC++;
    return SUCCESS;
}

int
rtexec_blt (uint64 * regs, struct ins *  inst) {
    if (S(R[RS1]) < S(R[RS2]))
        PC = inst->j;
    else
        PC++;
    return SUCCESS;
}

int
rtexec_bge (uint64 * regs, struct ins *  inst) {
    if (S(R[RS1]) >= S(R[RS2]))
        PC = inst->j;
    else
        PC++;
    return SUCCESS;
}

int
rtexec_ecall (uint64 * regs, struct ins *  inst) {
    (void) inst;
    R[X_A0] = ecall (R[X_A0], R[X_A1], R[X_A2]);
    PC++;
    return SUCCESS;
}

static int(*_rtexec[])(uint64*, struct ins *) = {
    [INS_ASGN]  rtexec_asgn,
    [INS_CAST]  rtexec_cast,
    [INS_LI]    rtexec_li,
    [INS_ADDI]  rtexec_addi,
    [INS_SLTI]  rtexec_slti,
    [INS_SLTIU] rtexec_sltiu,
    [INS_XORI]  rtexec_xori,
    [INS_ORI]   rtexec_ori,
    [INS_ANDI]  rtexec_andi,
    [INS_SLLI]  rtexec_slli,
    [INS_SRLI]  rtexec_srli,
    [INS_SRAI]  rtexec_srai,
    [INS_ADD]   rtexec_add,
    [INS_SUB]   rtexec_sub,
    [INS_SLL]   rtexec_sll,
    [INS_SLT]   rtexec_slt,
    [INS_SLTU]  rtexec_sltu,
    [INS_XOR]   rtexec_xor,
    [INS_SRL]   rtexec_srl,
    [INS_SRA]   rtexec_sra,
    [INS_OR]    rtexec_or,
    [INS_AND]   rtexec_and,
    [INS_NOT]   rtexec_not,
    [INS_LDI]   rtexec_ldi,
    [INS_STI]   rtexec_sti,
    [INS_LD]    rtexec_ld,
    [INS_ST]    rtexec_st,
    [INS_CALL]  rtexec_call,
    [INS_RET]   rtexec_ret,
    [INS_MV]    rtexec_mv,
    [INS_B]     rtexec_b,
    [INS_BEQ]   rtexec_beq,
    [INS_BNE]   rtexec_bne,
    [INS_BLT]   rtexec_blt,
    [INS_BGE]   rtexec_bge,
    [INS_ECALL] rtexec_ecall,
};

int
rtexec (uint64 * regs, struct ins *  inst) {
    //printf ("i:%d\n", inst->type);
    return _rtexec[inst->type](regs, inst);
}